package com.service.healthycode.service.impl;

import com.service.config.utils.*;
import com.service.healthycode.dao.AdminDao;
import com.service.healthycode.dao.UserDao;
import com.service.healthycode.dao.UserLoginRecordsDao;
import com.service.healthycode.dto.*;
import com.service.healthycode.entity.AdminInfo;
import com.service.healthycode.entity.UserInfo;
import com.service.healthycode.entity.UserLoginRecords;
import com.service.healthycode.rabbitmq.MsgProducer;
import com.service.healthycode.service.FeignMstscUnique;
import com.service.healthycode.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.service.config.constant.Constant.DATA_FORMAT_WRONG;
import static com.service.config.constant.Constant.USER_INFO_HEALTH_CODE;
import static com.service.healthycode.controller.UserController.clearCache;
import static com.service.healthycode.util.TransformationIp.getRealIp;

/**
 * @author: hjl
 * @date: 2022/04/12 15:57
 * @description
 */
@Slf4j
@Service
public class UserInfoServiceImpl implements UserInfoService {
    @Resource
    private AdminDao adminDao;
    @Resource
    private UserDao userDao;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private UserLoginRecordsDao loginRecordDao;
    @Resource
    FeignMstscUnique feignMstscUnique;


    @Override
    public UserInfo register(UserInfoDto userInfoDto, String realIp) {
        return getUserInfo(userInfoDto,realIp);
    }

    @Override
    public UserDto queryByUserId(String userId) {
        UserInfo userInfo = userDao.queryUserById(userId);
        if (null == userInfo) {
            return null;
        }
        UserDto userDto = ModelMapperUtil.strictMap(userInfo, UserDto.class);
        return userDto;
    }

    /**
     * 修改密码
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public Result updateUserInfo(UserInfoDto user) throws Exception {
        if (ObjectUtils.isEmpty(user.getCode())) {
            return Result.failure("请填写验证码");
        }

        if (redisUtil.exist(user.getCode())) {
            UserInfo info = userDao.queryUserById(user.getId());
            if (null == info) {
                return Result.failure(10001, "用户不存在");
            }
            if (null != user.getNewPassword() && !"".equals(user.getNewPassword())) {
                //修改密码
                UserInfo userInfo = userDao.queryUserInfoByTelephone(info.getTelephone(), user.getPassword());
                if (null != userInfo) {
                    if (user.getPassword().equals(user.getNewPassword())) {
                        return Result.failure(DATA_FORMAT_WRONG, "新旧密码不能一致");
                    }
                    userInfo.setPassword(user.getNewPassword());
                    userDao.update(userInfo);
                    Set<String> strings = redisUtil.redisLike(user.getId());
                    clearCache(strings, redisUtil);

                    String token = UserTokenManager.generateToken(userInfo.getId());
                    UserDto userDto = ModelMapperUtil.strictMap(userInfo, UserDto.class);
                    userDto.setOnlineTime(new Date()); //登录时间
                    redisUtil.setValue(token + userInfo.getId(), JsonXMLUtils.obj2json(userDto)); // 存入缓存
                    return Result.ok().setData(token);
                }
                return Result.failure(10015, "原密码输入错误");
            } else if ((null != user.getEmail() && !"".equals(user.getEmail()))
                    || (null != user.getTelephone()) && !"".equals(user.getTelephone())
                    || (null != user.getFullName()) && !"".equals(user.getFullName())
                    || (null != user.getIdNum()) && !"".equals(user.getIdNum())
                    || (null != user.getJobNum()) && !"".equals(user.getJobNum())
                    || (null != user.getTerminalMac() && !"".equals(user.getTerminalMac()))) {
                //修改用户信息(手机号和邮箱号)
                if (null != user) {
                    UserInfo userInfo1 = ModelMapperUtil.strictMap(user, UserInfo.class);
                    if (userInfo1.getTelephone() != null && userInfo1.getTelephone().length() != 11) {
                        return Result.failure(DATA_FORMAT_WRONG, "手机号格式有误");
                    }
                    if (userInfo1.getEmail() != null) {
                        String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
                        Pattern p = Pattern.compile(regEx1);
                        Matcher m = p.matcher(userInfo1.getEmail());
                        if (!m.matches()) {
                            return Result.failure(DATA_FORMAT_WRONG, "邮箱格式有误");
                        }
                    }
                    userDao.update(userInfo1);
                    return Result.ok();
                }
                return Result.failure(10016, "数据有误");
            }
            redisUtil.delete(user.getCode());
            return Result.failure(10016, "数据有误");
        }
        return Result.failure("当前验证码已失效，请重新验证");
    }



    /**
     *  新增用户
     * @param userInfoDto
     * @param realIp
     * @return
     */
    private UserInfo getUserInfo(UserInfoDto userInfoDto, String realIp) {
        UserInfo userInfo = ModelMapperUtil.strictMap(userInfoDto,UserInfo.class);
        UserInfo userInfo1 = userDao.queryUserByTel(userInfo.getTelephone());
        if (userInfo1 != null) {
            return null;
        }
        Result result = feignMstscUnique.addApiAccount();
        if (result.getCode() == 200) {
            userInfo.setId(result.getData().toString());
        }else {
            userInfo.setId(IdUtil.getStringId());
        }
        userInfo.setRoleId("1");
        userInfo.setRegisterTime(new Date());
        userDao.insert(userInfo);
        return userInfo;
    }

    /**
     * 用户登录获取token
     * @param loginUserDto
     * @param httpServletRequest
     * @return
     * @throws Exception
     */
    @Override
    public HashMap getToken(LoginUserDto loginUserDto, HttpServletRequest httpServletRequest) throws Exception {
        HashMap map = new HashMap();
        Object userInfo=null;
        if (loginUserDto.getRole()==1){
            userInfo = userDao.queryUserInfoByTelephone(loginUserDto.getTelephone(), loginUserDto.getPassword());
            if (userInfo == null || loginUserDto.getRole()==null || loginUserDto.getRole().equals("")) {
                return null;
            }
            UserInfo user = ModelMapperUtil.strictMap(userInfo, UserInfo.class);

        }else if (loginUserDto.getRole()==2){
            userInfo = adminDao.queryAdminInfo(loginUserDto.getAccount(), loginUserDto.getPassword());
            if (null == userInfo){
                return null;
            }
            AdminInfo admin = ModelMapperUtil.strictMap(userInfo, AdminInfo.class);
            if (admin.getRoleId()==null || admin.getRoleId().equals("")) {
                return null;
            }
        }

        return getHashMap(loginUserDto, httpServletRequest, map, userInfo);

    }

    @Override
    public UserInfo queryAll(LoginUserDto loginUserDto) {
        return userDao.queryUserInfoByTelephone(loginUserDto.getTelephone(),loginUserDto.getPassword());
    }

    /**
     * 根据强制登录标识符获取token
     * 强制标识符不存在且没有用户登录则直接返回token
     * 用户已登陆则直接返回用户重复登录码
     * @param loginUserDto
     * @param httpServletRequest
     * @param map
     * @param userInfo
     * @return
     * @throws Exception
     */
    private HashMap getHashMap(LoginUserDto loginUserDto, HttpServletRequest httpServletRequest, HashMap map, Object userInfo) throws Exception {
        String realIp = getRealIp(httpServletRequest);
        String token = "";
        Set<String> strings = null;
        Boolean isLogin = loginUserDto.getIsLogin();
        if (loginUserDto.getRole()==1){
            UserInfo user = (UserInfo)userInfo;

            UserDto userDto = ModelMapperUtil.strictMap(user, UserDto.class);
            userDto.setIp(realIp); // 来源ip
            userDto.setOnlineTime(new Date()); //登录时间

            strings = redisUtil.redisLike(user.getId());

            if (isLogin != null) {
                if (isLogin) {
                    token = UserTokenManager.generateToken(user.getId());
                    clearCache(strings, redisUtil);
                    HashMap map1 = setUserInfo(map, userDto, token,1);
                    return map1;
                }
            }
            if (strings.size() >= 1) {
                map.put("errorCode","用户重复登陆");
                return map ;
            }else {
                token = UserTokenManager.generateToken(user.getId());
                HashMap map1 = setUserInfo(map, userDto, token,1); //更新用户信息
                return map1;
            }
        }else{
            AdminInfo admin = (AdminInfo)userInfo;
            strings = redisUtil.redisLike(admin.getId());

            if (isLogin != null) {
                if (isLogin) { // 强制登录标识符
                    token = UserTokenManager.generateToken(admin.getId());
                    this.clearCache(strings, redisUtil);
                    HashMap map1 = setUserInfo(map, admin, token,2);
                    return map1;
                }
            }
            if (strings.size() >= 1) {
                map.put("errorCode","用户重复登陆");
                return map ;
            }else {
                token = UserTokenManager.generateToken(admin.getId());
                HashMap map1 = setUserInfo(map, admin, token,2); //更新用户信息
                return map1;
            }
        }


    }

    /**
     * 更新用户信息并返回token
     * @param map
     * @param token
     * @return
     * @throws Exception
     */
    private HashMap setUserInfo(HashMap map, Object userDto, String token,Integer role) throws Exception {
        if (role==1){
            UserDto dto = (UserDto) userDto;
            redisUtil.setValue(token+dto.getId(), JsonXMLUtils.obj2json(dto)); // 存入缓存
            map.put("Token",token);
            return map;
        }else {
            AdminInfo adminInfo = (AdminInfo) userDto;
            redisUtil.setValue(token+adminInfo.getId(), JsonXMLUtils.obj2json(adminInfo)); // 存入缓存
            map.put("Token",token);
            return map;
        }
    }

    public String getRealIp(HttpServletRequest request) {
        return getString(request);

    }
    public static String getString(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        ip = getString(request, ip);
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    public static String getString(HttpServletRequest request, String ip) {
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        return ip;
    }

    /**
     * 清除缓存
     * @param strings
     * @param redisUtil
     */
    public void clearCache(Set<String> strings, RedisUtil redisUtil) {
        strings.stream().forEach(
                s -> {
                    try {
                        redisUtil.delete(s);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
        );
    }
}
